package ro.gillardon.business.priceservice.impl.plane;

import static ro.gillardon.commons.config.ConfigParam.HTTP_PROXY_HOST;
import static ro.gillardon.commons.config.ConfigParam.HTTP_PROXY_PORT;

import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import ro.gillardon.business.exception.BusinessException;
import ro.gillardon.commons.config.ConfigParam;
import ro.gillardon.commons.config.ConfigProvider;
import ro.gillardon.commons.logger.BTPLogger;
import ro.gillardon.commons.mot.plane.PlaneConditions;

/**
 * Contains methods to navigate through the skyscanner.de web page, <br/>
 * fill input information and retrieve results. <br/>
 * Usage can be found in corresponding test class.
 *
 * @author ciolococ
 */
public class PlaneNavigator implements AutoCloseable {

  private static final Logger LOG = Logger.getLogger(PlaneNavigator.class);

  /** The Constant PROXY. */
  private static final String PROXY = getProperty(HTTP_PROXY_HOST) + ":" + getProperty(HTTP_PROXY_PORT);

  /** The 1 stops check box. */
  private static final String ONE_STOP_CHECK_BOX =
    getProperty(ConfigParam.BUSINESS_PRICESERVICE_PLANE_NAVIGATOR_CHECKBOX_ONESTOP);

  /** The 2+ stops check box. */
  private static final String TWO_PLUS_STOP_CHECK_BOX =
    getProperty(ConfigParam.BUSINESS_PRICESERVICE_PLANE_NAVIGATOR_CHECKBOX_TWOSTOP);

  /** The result list of offers from the site. */
  private static final String RESULT = getProperty(ConfigParam.BUSINESS_PRICESERVICE_PLANE_NAVIGATOR_RESULT);

  /** The direct combo box. */
  private static final String DIRECT = getProperty(ConfigParam.BUSINESS_PRICESERVICE_PLANE_NAVIGATOR_CHECKBOX_DIRECT);

  /** The URL that needs to be completed by other inputs. */
  private String url = getProperty(ConfigParam.BUSINESS_PRICESERVICE_PLANE_NAVIGATOR_URL);

  /**
   * Helper method to initialize fields.
   *
   * @param param the configParam
   * @return the property value
   */
  private static String getProperty(final ConfigParam param) {
    return ConfigProvider.getProperty(param);
  }

  /** The driver. */
  private final WebDriver driver;

  /**
   * Instantiates a new plane navigator driver.
   */
  public PlaneNavigator() {
    final Proxy proxy = new Proxy().setHttpProxy(PROXY).setFtpProxy(PROXY).setSslProxy(PROXY);
    final DesiredCapabilities cap = new DesiredCapabilities();
    cap.setCapability(CapabilityType.PROXY, proxy);
    cap.setCapability(CapabilityType.SUPPORTS_JAVASCRIPT, true);
    this.driver = new FirefoxDriver(cap);
  }

  /**
   * Close driver.
   */
  @Override
  public void close() {
    this.driver.close();
  }

  /**
   * Navigate through page.
   *
   * @param conditions the plane conditions
   * @throws BusinessException
   */
  public void navigateToPage(final PlaneConditions conditions) throws BusinessException {

    this.driver.navigate().to(getURLToNavigate(conditions));
    if (!existDirectFlights()) {
      throw new BusinessException();
    }
    clickOneStopCheckBox();
    clickTwoStopsCheckBox();

  }

  /**
   * Search the direct check box on the left side of the site to verify if the check box is enabled . If enabled ,<br/>
   * there are direct flights for that date.
   *
   * @return true if exist , false is not
   */
  private boolean existDirectFlights() {
    try {
      final WebElement direct = this.driver.findElement(By.id(DIRECT));
      if (direct.isEnabled()) {
        return true;
      }
    } catch (final NoSuchElementException e) {
      BTPLogger.error(LOG, "Direct check box is disabled. Details :" + e);
    }
    return false;

  }

  /**
   * Click on the 1 stop check box , if exists , to narrow the search and find the direct flights.
   */
  private void clickOneStopCheckBox() {
    try {
      final WebElement oneStop = this.driver.findElement(By.id(ONE_STOP_CHECK_BOX));
      oneStop.click();
    } catch (final NoSuchElementException e) {
      BTPLogger.error(LOG, "1 stop check box is disabled. Details :" + e);
    }
  }

  /**
   * Click on the 2+ stops check box , if exists , to narrow the search and find the direct flights.
   */
  private void clickTwoStopsCheckBox() {
    try {
      final WebElement twoStops = this.driver.findElement(By.id(TWO_PLUS_STOP_CHECK_BOX));
      twoStops.click();
    } catch (final NoSuchElementException e) {

      BTPLogger.error(LOG, " 2+ stops check box is disabled. Details :" + e);
    }
  }

  /**
   * Gets the result list of direct flights as raw HTML.
   */
  public String getResults() {
    final WebElement result = this.driver.findElement(By.id(RESULT));
    return result.getAttribute("innerHTML");

  }

  /**
   * Build the URL from the Plane Conditions.
   */
  private String getURLToNavigate(final PlaneConditions conditions) {

    final String fromCityCode = conditions.getFrom().getCode();
    final String toCityCode = conditions.getTo().getCode();
    final String departDate = conditions.getDepartureDate().toString();
    final String arrivalDate = conditions.getArrivalDate().toString();

    this.url = this.url + fromCityCode.toLowerCase() + "/"
      + toCityCode.toLowerCase() + "/"
      + formatDate(departDate) + "/"
      + formatDate(arrivalDate) + "/";
    return this.url;
  }

  /**
   * Format the date to insert in the URL.
   */
  private String formatDate(final String departDate) {
    return departDate.replace("-", "").substring(2);
  }
}
